package lee.vioson.ebook.viewmodels

import androidx.lifecycle.viewModelScope
import com.luck.picture.lib.entity.LocalMedia
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import lee.vioson.composecommon.base.mvi.Reducer
import lee.vioson.composecommon.base.mvi.UiEvent
import lee.vioson.composecommon.base.mvi.UiState
import lee.vioson.composecommon.isNotEmpty
import lee.vioson.ebook.data.AppContainer
import lee.vioson.ebook.data.picUrl
import lee.vioson.remotedata.bean.UploadState
import lee.vioson.remotedata.bean.requestbody.FeedbackBody
import lee.vioson.remotedata.bean.requestbody.FeedbackType
import java.util.UUID

/**
 *Author:viosonlee
 *Date:2023/6/12
 *DESCRIPTION:
 */
class FeedbackViewModel(private val appContainer: AppContainer) :
    AppViewModel<FeedbackViewModel.State, FeedbackViewModel.Event>(appContainer.appEvent) {

    private val reducer = SubReducer(State())

    override val state: StateFlow<State>
        get() = reducer.state

    override fun sendEvent(event: Event) {
        reducer.sendEvent(event)
    }

    val feedbackTypeList = FeedbackType.values().toMutableList()

    fun onSelectPicList(list: List<LocalMedia>) {
        sendEvent(Event.OnAddPic(list))
        //upload pic
        state.value.picList.forEach { uploadPic ->
            uploadFile(uploadPic).launchIn(viewModelScope)
        }
    }

    fun uploadFile(uploadPic: UploadPic) = flow<UploadState> {
        delay(1000)
        emit(UploadState.Success(picUrl))
    }
        .catch { handleException(it) }
        .onEach {
            when (it) {
                is UploadState.Success -> {
                    sendEvent(
                        Event.OnUploadPicChange(
                            uploadPic.copy(
                                isUploaded = true,
                                uploadProcess = 1f,
                                remoteUrl = it.remoteUrl
                            )
                        )
                    )
                }

                is UploadState.InProgress -> {
                    sendEvent(Event.OnUploadPicChange(uploadPic.copy(uploadProcess = it.progress)))
                }

                is UploadState.Error -> {
                    sendEvent(
                        Event.OnUploadPicChange(
                            uploadPic.copy(
                                uploadProcess = 0f,
                                uploadError = true,
                                remoteUrl = null,
                                isUploaded = false
                            )
                        )
                    )
                }
            }
        }


    /**
     * commit feedback
     */
    fun commit(feedbackBody: FeedbackBody) =
        appContainer.feedbackRepository.commitFeedback(feedbackBody)
            .catch { handleException(it) }
            .onStart { showLoading() }
            .onCompletion { dismissLoading() }
            .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
            .launchIn(viewModelScope)

    class SubReducer(initialState: State) :
        Reducer<State, Event>(initialState) {
        override fun reduce(oldState: State, event: Event) {
            when (event) {
                is Event.OnTypeSelect -> {
                    setState(
                        oldState.copy(
                            type = event.type,
                            enable = oldState.picList.none { !it.isUploaded } && oldState.inputContent.isNotEmpty
                        )
                    )
                }

                is Event.OnInputContent -> {
                    setState(
                        oldState.copy(
                            inputContent = event.content,
                            enable = oldState.type != null && oldState.picList.none { !it.isUploaded }
                                    && event.content.isNotEmpty
                        )
                    )
                }

                is Event.OnAddPic -> {
                    val list = oldState.picList.toMutableList()
                    event.uploadPics?.forEach {
                        list.add(UploadPic(it.path))
                    }
                    setState(
                        oldState.copy(
                            picList = list, enable = oldState.type != null &&
                                    list.none { !it.isUploaded } &&
                                    oldState.inputContent.isNotEmpty
                        )
                    )
                }

                is Event.OnDeletePic -> {
                    val list = oldState.picList.toMutableList()
                    list.removeAt(event.index)
                    setState(
                        oldState.copy(
                            picList = list, enable = oldState.type != null &&
                                    list.none { !it.isUploaded } &&
                                    oldState.inputContent.isNotEmpty
                        )
                    )
                }

                is Event.OnUploadPicChange -> {
                    val uploadPic = event.uploadPic
                    val list = oldState.picList.toMutableList()
                    val index = list.indexOfLast { it.id == uploadPic.id }
                    if (index >= 0) {
                        list[index] = uploadPic
                    }
                    setState(
                        oldState.copy(
                            picList = list,
                            enable = oldState.type != null &&
                                    oldState.inputContent.isNotEmpty &&
                                    list.none { !it.isUploaded })
                    )
                }
            }
        }
    }


    sealed class Event : UiEvent {
        data class OnTypeSelect(val type: FeedbackType) : Event()
        data class OnInputContent(val content: String) : Event()
        data class OnAddPic(val uploadPics: List<LocalMedia>?) : Event()
        data class OnDeletePic(val index: Int) : Event()
        data class OnUploadPicChange(val uploadPic: UploadPic) : Event()
    }

    data class State(
        val type: FeedbackType? = null,
        val picList: List<UploadPic> = emptyList(),
        val inputContent: String = "",
        val enable: Boolean = false,
    ) : UiState

    data class UploadPic(
        val localPath: String,
        val remoteUrl: String? = null,
        val isUploaded: Boolean = false,
        val uploadProcess: Float = 0f,
        val uploadError: Boolean = false,
        val id: String = UUID.randomUUID().toString()
    ) {
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as UploadPic

            if (localPath != other.localPath) return false
            if (id != other.id) return false

            return true
        }

        override fun hashCode(): Int {
            var result = localPath.hashCode()
            result = 31 * result + id.hashCode()
            return result
        }
    }
}

